You can't make callouts, HTTP or otherwise, once you have made changes to the database. It's true that you cannot make callouts with pending transactions in the request context. Also, it's not possible to do an explicit commit. So your only way out is to make the callout in a separate context.
You cannot perform a DML operation prior to a callout. All the DML operations should be invoked only after you are done with callouts.So, make a webservice callout first and then save the request.
If you are making multiple callouts, then save all the requests in a list or map and post callouts you save them.
Basically the following scenario will work :-
query
callout
query
callout
insert
callout
callout
callout
insert or update
But the following scenario will fail :-
callout
insert
callout <---- fails here
Possible workaround :-
1) You either need to commit the transaction, make the callout prior to any database changes or move your callout to an @future method (place @future annotation to the webservice method).
2) Splits the transaction into two separate Ajax processes. The first inserts the record and the second performs the callout and is able to update the newly inserted record.
You can save the records and then respond to the user with a temporary page with a "Loading" message as you make the second call back to perform the callout. To make it look seamless, you can also make successive AJAX calls to save records and to make callout as user sees "Loading" message upon clicking "Save" button.
4) Sometimes customer do not want to place @future annotation to the webservice method as they need a response from the webservice to decide if they have to rollback the insert or not ?
They can execute an action to insert the object and then execute the webservice callout on the oncomplete event of a commandButton. Then, return a PageReference giving the user immediate feedback.
If the webservice callout returns any error, then delete the object and returning the user back to the same page.
See bellow:
@VisualforcePage
<apex:actionFunction name="executeWS" action="{!executeWS}"></apex:actionFunction>
<apex:commandButton value="Save" action="{!save}" oncomplete="executeWS()" />
@Controller
public PageReference save() {
insert obj;
}
public PageReference executeWS(){
obj = [SELECT ...];
try{
callout ws;
} catch(System.Exception ex){
delete obj;
ApexPages.addMessages(e);
return null;
}
return new PageReference('/' + id);
}